"""
因为缠论文章都是博客形式，并无很规范的写作格式与篇章结构，自己理解起来着实不易，每次读都感悟不同，程序也是改了又改。
       下文对于缠论的理解以及程序的处理都是个人粗浅的理解，还望对缠论有很深造诣的前辈指出不足之处。

一、序言
       研究模块中实现了“缠论”的分型，笔，线段。
       开始本想实现维克多交易法则中的维克多交易法则，维克多123法则和2B法则是判断趋势变动的最基本法则。思考如何实现对于趋势"图"的识别，想到了缠论中关于分型，笔以及线段的描述。
       其中对简单的1-2-3准则的进行简单总结：

趋势线被突破。价格穿越绘制的趋势线
上升趋势不再创新高，或下降趋势不再创新低。
在下降趋势中，价格向上穿越先前的短期反弹高点；或在上升趋势中，价格向下穿越先前的短期回档低点。
       示意图如下所示：
图1图2
       维克多交易规则具体的学习还是要到《专业投机原理》一书中深刻领会，在这里仅仅是一个概括。
       我们可以将维克多的趋势看为缠论的一个线段，维克多的趋势破坏即可认为是缠论中的线段被破坏，如下图中9所示，触发交易信号。下面介绍一下缠论之分型、笔、线段。

二、缠论之分型、笔、线段
       下面的定义与图，都适合任何周期的 K 线图。先看图中的第 1、2，图中的小线段代表的是 K 线，这里不分阳线阴线，只看 K 线高低点。
缠论

       像图1这种，第二K线高点是相邻三K线高点中最高的，而低点也是相邻三K线低点中最高的，定义其顶分型；图2这种第二K线低点是相邻三K线低点中最低的，而高点也是相邻三K线高点中最低的，定义为底分型。看不明白定义的，看图就明白了。

       顶分型的最高点叫该分型的顶，底分型的最低点叫该分型的底，由于顶分型的底和底分型的顶是没有意义的，所以顶分型的顶和底分型的底就可以简称为顶和低。也就是说，当我们以后说顶和底时，就分别是说顶分型的顶和底分型的底。

       两个相邻的顶和底之间构成一笔，所谓笔，就是顶和底之间的其他波动，都可以忽略不算，但注意，一定是相邻的顶和底，隔了几个就不是了。而所谓的线段，就是至少由三笔组成。但这里有一个细微的地方要分清楚，因为结合律是必须遵守的，像图3这种，顶和底之间必须共用一个K线，这就违反结合律了，所以这不算一笔，而图4，就光是顶和底了，中间没有其他K线，一般来说，也最好不算一笔，而图5，是一笔的最基本的图形，顶和底之间还有一根K线。在实际分析中，都必须要求顶和底之间都至少有一K线当成一笔的最基本要求。

       当然，实际图形里，有些复杂的关系会出现，就是相邻两K线可以出现如图6这种包含关系，也就是一K线的高低点全在另一K线的范围里，这种情况下，可以这样处理，在向上时，把两K线的最高点当高点，而两K线低点中的较高者当成低点，这样就把两K线合并成一新的K线；反之，当向下时，把两K线的最低点当低点，而两K线高点中的较低者当成高点，这样就把两K线合并成一新的K线。经过这样的处理，所有K线图都可以处理成没有包含关系的图形。在我的处理中，将下方这些形式都进行了包含关系的处理。
包含处理

       而图7，就给出了经过以上处理，没有包含关系的图形中，三相邻K线之间可能组合的一个完全分类，其中的二、四，就是分别是顶分型和底分型，一可以叫上升K线，三可以叫下降K线。所以，上升的一笔，由结合律，就一定是底分型+上升K线+顶分型；下降的一笔，就是顶分型+下降K线+底分型。注意，这里的上升、下降K线，不一定都是3根，可以无数根，只要一直保持这定义就可以。当然，简单的，也可以是1、2根，这只要不违反结合律和定义就可以。

       至于图8，就是线段的最基本形态，而图9，就是线段破坏，也就是两线段组合的其中一种形态。
       有人可能要说，这怎么有点像波浪理论，缠论作者认为这不奇怪，作者认为缠论的理论可以严格地推论出波浪理论的所有结论，而且还可以指出他理论的所有不足，波浪理论和缠论的理论一点可比性都没有。不仅是波浪理论，所有关于股市的理论，只要是关系到“图形”的，缠论的理论都可以严格推论，因为缠论的理论是关于走势图形最基础的理论，谁都逃不掉。

       缠论中根据可操作性定义了不同显微级别的，对于中枢和走势类型，也就有了关于不同级别的图形的研究。进而，就有了不同级别显微镜的比喻。而实际上，一般能得到的图，最多也就是 1 分钟级别的，因此，可以从这个图入手。当然，也可以从 5 分钟，甚至更高入手，但这就等于把显微镜倍数弄小了，看到的东西自然没有 1 分钟的多且清楚。再次强调，什么级别的图和什么级别的中枢没有任何必然关系，走势类型以及中枢就如同显微镜下的观察物，是客观存在的，其存在性由上面所说最原始的递归定义保证，而级别的图，就如同显微镜，不同倍数的看这客观的图就看到不同的精细程度，如此而已。所以，不能把显微镜和显微镜观察的东西混在一起了。

       如果我们首先确立了显微镜的倍数，也就是说，例如我们把 1 分钟图作为最基本的图，那么就可以开始定义上一课程说的分型、笔、线段等等。有了线段，就可以定义 1 分钟的中枢，然后就是 1 分钟的走势类型，然后按照递归的方法，可以逐步定义 5 分钟、30 分钟、日、周、月、季度、年的中枢和走势类型。而有的人总是不明白，例如总是在问，5 分钟图怎么看，30 分钟怎么看，其实，如果你选择 5 分钟或 30 分钟为最基本的图，那么和 1 分钟的看法一样，只不过你的显微镜倍数比较小，看起来比较粗糙而已。而如果你已经选择 1 分钟作为最基本的图，也就是选定了 1 分钟这个倍数的显微镜，那么看 1 分钟图就可以。

       所以程序中也定义了换算不同分钟级别的函数get_Fnk，根据需求可获得不同级别的分钟数据。

       另外，鄙人对于分型的寻找，如果一个底分型之后遇到一个顶分型，其中底分型的底高于顶分型的顶，如下图中一所示，则上一个底分型不被确立，跳过该顶分型，接着寻找一个下一个更低的底分型或者顶高于该底分型的顶分型。（话着实有些绕，抱歉抱歉！看图您就明白了。）
图

       缠论具体细则可参考《教你炒股票-缠中说禅》，其中关于“分型，笔，线段”的内容可参考第62-65课的内容。

用缠论分型处理之后的图形如下，符合维克多上升趋势：
维克多

三、不足之处
因为思绪混乱，程序更改多次，看着也许会有些混乱；
判断包含关系、找寻顶底的程序没有写成函数；
因为要实现维克多交易规则，程序还要判断准则还需更改，所以暂时并未没有实现，下一步计划实现维克多1-2-3与维克多2B交易规则。
"""
def get_Fnk(security, start, end, n=5):
    '''
    获得k分钟k线函数
    '''
    import pandas as pd
    k_data = get_price(security, start_date=start, end_date=end, frequency='minute', fields=['open','close','high', 'low'])

    # 去除9:00与13:00的数据
    for i in range(len(k_data)/242):
        team = list(k_data.index)
        x = [s.strftime("%Y-%m-%d %H:%M:%S") for s in team]
        y = filter(lambda t : "09:31:00" in t, x)
        k_data= k_data.drop(k_data.index[x.index(y[0])])
        del x[x.index(y[0])]
        y = filter(lambda t : "13:01:00" in t, x)
        k_data= k_data.drop(k_data.index[x.index(y[0])])
        del x[x.index(y[0])]

    # 计算n分钟K线
    Fnk = pd.DataFrame()
    for i in xrange(n,len(k_data)+1,n):
        temp = k_data[i-n : i]
        temp_open = temp.open[0]
        temp_high = max(temp.high)
        temp_low = min(temp.low)
        temp_k = temp[-1:]
        temp_k.open = temp_open
        temp_k.high = temp_high
        temp_k.low = temp_low
        Fnk = pd.concat([Fnk,temp_k],axis = 0)
    return Fnk

def middle_num(k_data):
    # 鸡肋函数，完全的强迫症所为，只为下面画图时candle图中折线时好看而已 - -！
    # k_data 为DataFrame格式
    plot_data=[]
    for i in xrange(len(k_data)):
        temp_y = (k_data.high[i]+k_data.low[i])/2.0
        plot_data.append(temp_y)
    return plot_data

#_______________________________________________
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.finance as mpf

k_data = get_Fnk(n=5, security='000001.XSHE', start='2015-12-02', end='2015-12-05')

## 判断包含关系
after_fenxing = pd.DataFrame()
temp_data = k_data[:1]
zoushi = [3]  # 3-持平 4-向下 5-向上
for i in xrange(len(k_data)):
    case1_1 = temp_data.high[-1] > k_data.high[i] and temp_data.low[-1] < k_data.low[i]  # 第1根包含第2根
    case1_2 = temp_data.high[-1] > k_data.high[i] and temp_data.low[-1] == k_data.low[i]  # 第1根包含第2根
    case1_3 = temp_data.high[-1] == k_data.high[i] and temp_data.low[-1] < k_data.low[i]  # 第1根包含第2根
    case2_1 = temp_data.high[-1] < k_data.high[i] and temp_data.low[-1] > k_data.low[i]  # 第2根包含第1根
    case2_2 = temp_data.high[-1] < k_data.high[i] and temp_data.low[-1] == k_data.low[i]  # 第2根包含第1根
    case2_3 = temp_data.high[-1] == k_data.high[i] and temp_data.low[-1] > k_data.low[i]  # 第2根包含第1根
    case3 = temp_data.high[-1] == k_data.high[i] and temp_data.low[-1] == k_data.low[i]  # 第1根等于第2根
    case4 = temp_data.high[-1] > k_data.high[i] and temp_data.low[-1] > k_data.low[i]  # 向下趋势
    case5 = temp_data.high[-1] < k_data.high[i] and temp_data.low[-1] < k_data.low[i]  # 向上趋势
    if case1_1 or case1_2 or case1_3:
        if zoushi[-1] == 4:
            temp_data.high[-1] = k_data.high[i]
        else:
            temp_data.low[-1] = k_data.low[i]

    elif case2_1 or case2_2 or case2_3:
        temp_temp = temp_data[-1:]
        temp_data = k_data[i:i + 1]
        if zoushi[-1] == 4:
            temp_data.high[-1] = temp_temp.high[0]
        else:
            temp_data.low[-1] = temp_temp.low[0]

    elif case3:
        zoushi.append(3)
        pass

    elif case4:
        zoushi.append(4)
        after_fenxing = pd.concat([after_fenxing, temp_data], axis=0)
        temp_data = k_data[i:i + 1]

    elif case5:
        zoushi.append(5)
        after_fenxing = pd.concat([after_fenxing, temp_data], axis=0)
        temp_data = k_data[i:i + 1]
# after_fenxing.head()

#_____________________________________
## 因为使用candlestick2函数，要求输入open、close、high、low。为了美观，处理k线的最大最小值、开盘收盘价，之后k线不显示影线。
for i in xrange(len(after_fenxing)):
    if after_fenxing.open[i] > after_fenxing.close[i]:
        after_fenxing.open[i] = after_fenxing.high[i]
        after_fenxing.close[i] = after_fenxing.low[i]
    else:
        after_fenxing.open[i] = after_fenxing.low[i]
        after_fenxing.close[i] = after_fenxing.high[i]

## 画出k线图
stock_middle_num = middle_num(after_fenxing)
fig, ax = plt.subplots(figsize = (50,20))
fig.subplots_adjust(bottom=0.2)
mpf.candlestick2(ax, list(after_fenxing.open),list(after_fenxing.close),list(after_fenxing.high),list(after_fenxing.low), width=0.6, colorup='r', colordown='b',alpha=0.75 )
plt.grid(True)
dates = after_fenxing.index
ax.set_xticklabels(dates) # Label x-axis with dates
# ax.autoscale_view()
plt.plot(stock_middle_num,'k', lw=1)
plt.plot(stock_middle_num,'ko')
plt.setp(plt.gca().get_xticklabels(), rotation=30)
#___________________________________________________
## 找出顶和底
temp_num = 0  # 上一个顶或底的位置
temp_high = 0  # 上一个顶的high值
temp_low = 0  # 上一个底的low值
temp_type = 0  # 上一个记录位置的类型
i = 1
fenxing_type = []  # 记录分型点的类型，1为顶分型，-1为底分型
fenxing_time = []  # 记录分型点的时间
fenxing_plot = []  # 记录点的数值，为顶分型去high值，为底分型去low值
fenxing_data = pd.DataFrame()  # 分型点的DataFrame值
while (i < len(after_fenxing) - 1):
    case1 = after_fenxing.high[i - 1] < after_fenxing.high[i] and after_fenxing.high[i] > after_fenxing.high[
        i + 1]  # 顶分型
    case2 = after_fenxing.low[i - 1] > after_fenxing.low[i] and after_fenxing.low[i] < after_fenxing.low[i + 1]  # 底分型
    if case1:
        if temp_type == 1:  # 如果上一个分型为顶分型，则进行比较，选取高点更高的分型
            if after_fenxing.high[i] <= temp_high:
                i += 1
            #                 continue
            else:
                temp_high = after_fenxing.high[i]
                temp_num = i
                temp_type = 1
                i += 4
        elif temp_type == 2:  # 如果上一个分型为底分型，则记录上一个分型，用当前分型与后面的分型比较，选取同向更极端的分型
            if temp_low >= after_fenxing.high[i]:  # 如果上一个底分型的底比当前顶分型的顶高，则跳过当前顶分型。
                i += 1
            else:
                fenxing_type.append(-1)
                fenxing_time.append(after_fenxing.index[temp_num].strftime("%Y-%m-%d %H:%M:%S"))
                fenxing_data = pd.concat([fenxing_data, after_fenxing[temp_num:temp_num + 1]], axis=0)
                fenxing_plot.append(after_fenxing.high[i])
                temp_high = after_fenxing.high[i]
                temp_num = i
                temp_type = 1
                i += 4
        else:
            temp_high = after_fenxing.high[i]
            temp_num = i
            temp_type = 1
            i += 4

    elif case2:
        if temp_type == 2:  # 如果上一个分型为底分型，则进行比较，选取低点更低的分型
            if after_fenxing.low[i] >= temp_low:
                i += 1
            #                 continue
            else:
                temp_low = after_fenxing.low[i]
                temp_num = i
                temp_type = 2
                i += 4
        elif temp_type == 1:  # 如果上一个分型为顶分型，则记录上一个分型，用当前分型与后面的分型比较，选取同向更极端的分型
            if temp_high <= after_fenxing.low[i]:  # 如果上一个顶分型的底比当前底分型的底低，则跳过当前底分型。
                i += 1
            else:
                fenxing_type.append(1)
                fenxing_time.append(after_fenxing.index[temp_num].strftime("%Y-%m-%d %H:%M:%S"))
                fenxing_data = pd.concat([fenxing_data, after_fenxing[temp_num:temp_num + 1]], axis=0)
                fenxing_plot.append(after_fenxing.low[i])
                temp_low = after_fenxing.low[i]
                temp_num = i
                temp_type = 2
                i += 4
        else:
            temp_low = after_fenxing.low[i]
            temp_num = i
            temp_type = 2
            i += 4

    else:
        i += 1
#_________________

print fenxing_type
print fenxing_time
print fenxing_plot
fenxing_data

#------------------------
fig, ax = plt.subplots(figsize = (20,5))
dates = fenxing_data.index
ax.set_xticklabels(dates) # Label x-axis with dates
ax.autoscale_view()
plt.plot(fenxing_plot,'k', lw=1)
plt.plot(fenxing_plot,'o')
plt.grid(True)
plt.setp(plt.gca().get_xticklabels(), rotation=30)